# get config and env
import os
import sys
import json
import ctypes
from socket import timeout
from urllib.request import urlopen
from common.enum import MyEnum
from common.utils import get_linux_platform


class Config(object):

    def __init__(self, project_root, config):
        # 根目录
        self.project_root = project_root
        self.root_pprogram = None
        self.pprogram = None
        self.platform, self.codename, self.version = get_platform()
        self.bash_alias = None
        self.bash_cmd = None
        self.py_module = None
        self.dev_soft = None
        self.laptop_soft = None
        self.official_repo = None
        self.third_repo = None
        # 环境变量
        self.env = dict()
        self.set_config(config)
        self.set_env(config)

    def set_env(self, config):
        if self.is_win():
            return
        else:
            # official_repo
            import pwd
            # get *unix env
            user = pwd.getpwuid(1000)
            self.env[MyEnum.user_name.value] = user.pw_name
            self.env[MyEnum.user_home.value] = user.pw_dir
            self.env[MyEnum.config_root.value] = self.project_root+"/common"
            # mirror name, select ustc first
            try:
                Checker.chk_url(config[MyEnum.ustc.value])
                Checker.chk_url(config[MyEnum.ustc.value + "_pypi"])
                self.env[MyEnum.mirror_name.value] = MyEnum.ustc.value
            except timeout:
                Checker.chk_url(config[MyEnum.tuna.value])
                Checker.chk_url(config[MyEnum.tuna.value + "_pypi"])
                self.env[MyEnum.mirror_name.value] = MyEnum.tuna.value
            mirror_name = self.env[MyEnum.mirror_name.value]
            self.env[MyEnum.pip_index.value] = config[mirror_name + "_pypi"]
            self.env[MyEnum.mirror_url.value] = config[mirror_name]
            self.env[MyEnum.linux_version.value] = self.version
            # specified variable name
            if self.platform == "opensuse":
                self.env[MyEnum.full_suse_version.value] = 'openSUSE_Leap_%s' % self.version
            elif self.platform == "ubuntu":
                self.env[MyEnum.ubuntu_code_name] = self.codename

    def set_config(self, config):
        if self.is_win():
            # need portable program path and project portable program path
            self.root_pprogram = self.project_root + "/common/pprogram"
            self.pprogram = config[MyEnum.win.value][MyEnum.pprogram.value]
        else:
            # bash: 别称， 命令， pip requirements 文件地址
            self.bash_alias = config[MyEnum.bash.value][MyEnum.bash_alias.value]
            self.bash_cmd = config[MyEnum.bash.value][MyEnum.bash_cmd.value]
            self.py_module = config[MyEnum.py_module_file.value]
            if self.is_opensuse():
                suse_env = config[MyEnum.opensuse.value]
                self.dev_soft = suse_env[MyEnum.dev_soft.value]
                self.laptop_soft = suse_env[MyEnum.laptop_soft.value]
                self.official_repo = suse_env[MyEnum.official_repos.value]
                self.third_repo = suse_env[MyEnum.third_repos.value]
            elif self.is_ubuntu():
                pass

    def is_win(self):
        return self.platform == "win"

    def is_opensuse(self):
        return self.platform == "opensuse"

    def is_ubuntu(self):
        return self.platform == "ubuntu"


class Checker(object):
    def __init__(self, conf):
        self.conf = conf
        self.platform = sys.platform

    def check_win(self):
        if self.platform[:3] != "win":
            return
        self.check_key_exist([MyEnum.win.value, MyEnum.pprogram.value])
        # pprogram
        self.check_path_exists(self.conf[MyEnum.win.value][MyEnum.pprogram.value])

    def check_linux(self):
        if self.platform[:3] == "win":
            return
        # check key
        print("checking mirror")
        self.check_key_exist([MyEnum.ustc.value])
        self.check_key_exist([MyEnum.tuna.value])
        self.check_key_exist([MyEnum.ustc.value+"_pypi"])
        self.check_key_exist([MyEnum.tuna.value + "_pypi"])
        print("checking bash misc")
        self.check_key_exist([MyEnum.py_module_file.value])
        self.check_key_exist([MyEnum.sudo_cmd.value])
        self.check_key_exist([MyEnum.normal_cmd.value])
        self.check_key_exist([MyEnum.bash.value, MyEnum.bash_alias.value])
        self.check_key_exist([MyEnum.bash.value, MyEnum.bash_cmd.value])
        print("checking os related config")
        self.check_key_exist([MyEnum.opensuse.value, MyEnum.dev_soft.value])
        self.check_key_exist([MyEnum.opensuse.value, MyEnum.laptop_soft.value])
        self.check_key_exist([MyEnum.opensuse.value, MyEnum.third_repos.value])
        self.check_key_exist([MyEnum.opensuse.value, MyEnum.official_repos.value])
        self.check_key_exist([MyEnum.ubuntu.value, MyEnum.dev_soft.value])
        self.check_key_exist([MyEnum.ubuntu.value, MyEnum.laptop_soft.value])
        self.check_key_exist([MyEnum.ubuntu.value, MyEnum.third_repos.value])
        self.check_key_exist([MyEnum.ubuntu.value, MyEnum.official_repos.value])

    def check_key_exist(self, key_list):
        key = ""
        conf = self.conf
        for k in key_list:
            key += "/" + k
            if k not in conf:
                raise Exception("key %s not in configure file" % key)
            conf = conf[k]

    @staticmethod
    def check_path_exists(to_be_check):
        if not os.path.exists(to_be_check):
            raise Exception("path %s does not exists" % to_be_check)

    @staticmethod
    def chk_url(url, time_out=30):
        try:
            urlopen(url, timeout=time_out).read()
        except timeout:
            raise Exception('Can not access %s' % url)

    @staticmethod
    def check_permission():
        try:
            return os.getuid() == 0
        except AttributeError:
            return ctypes.windll.shell32.IsUserAnAdmin() != 0


def new_config(config_path=""):
    here = os.path.dirname(__file__)
    # get config file (json)
    if config_path == "":
        config_path = here+"/configs.json"
    # check pre requirement
    if not os.path.exists(here+"/pprogram"):
        os.mkdir(here+"/pprogram", 777)
    if not os.path.exists(here+"/pkg"):
        os.mkdir(here+"/pkg")
    Checker.check_path_exists(config_path)
    config = json.load(open(config_path))
    chk = Checker(config)
    chk.check_win()
    chk.check_linux()

    # get config
    project_root = os.path.dirname(here)
    conf = Config(project_root, config)
    if not chk.check_permission():
        raise Exception("please run in admin mode")
    return conf


# helper function
def get_platform():
    if sys.platform[:3] == MyEnum.win.value:
        return MyEnum.win.value, "", ""
    name, codename, version = get_linux_platform()
    if name not in ["ubuntu", "opensuse"]:
        raise Exception("only ubuntu or opensuse supported not %s" % sys.platform)
    return name, codename, version
